package com.birds.portal.servlet;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
 * this is a common Class work with Json
 * 
 * @author Gale Yan 2008-11-22
 */
public abstract class JsonUtil {

	/**
	 * Encapsulate <code>Object</code> to a JSON String
	 * 
	 * @param o
	 *            Oject
	 * @return JSON JSON String
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static String toJson(final Object o) {
		if (o == null) {
			return "null";
		}
		if (o instanceof String) // String
		{
			return string2Json((String) o);
		}
		if (o instanceof Boolean) // Boolean
		{
			return boolean2Json((Boolean) o);
		}
		if (o instanceof Number) // Number
		{
			return number2Json((Number) o);
		}
		if (o instanceof Map) // Map
		{
			return map2Json((Map<String, Object>) o);
		}
		if (o instanceof Collection) // List Set
		{
			return collection2Json((Collection) o);
		}
		if (o instanceof Object[]) // List of object
		{
			return array2Json((Object[]) o);
		}

		if (o instanceof int[])// int type
		{
			return intArray2Json((int[]) o);
		}
		if (o instanceof boolean[])// boolean type
		{
			return booleanArray2Json((boolean[]) o);
		}
		if (o instanceof long[]) {
			return longArray2Json((long[]) o);
		}
		if (o instanceof float[]) {
			return floatArray2Json((float[]) o);
		}
		if (o instanceof double[]) {
			return doubleArray2Json((double[]) o);
		}
		if (o instanceof short[]) {
			return shortArray2Json((short[]) o);
		}
		if (o instanceof byte[]) {
			return byteArray2Json((byte[]) o);
		}
		if (o instanceof Object) {
			return object2Json(o);
		}

		throw new RuntimeException("No support type Object:"
				+ o.getClass().getName());
	}

	/**
	 * Change a String to an JSON String
	 * 
	 * @param s
	 *            a String
	 * @return a JSON String
	 */
	public static String string2Json(final String s) {
		final StringBuilder sb = new StringBuilder(s.length() + 20);
		sb.append('\"');
		for (int i = 0; i < s.length(); i++) {
			final char c = s.charAt(i);
			switch (c) {
			case '\"':
				sb.append("\\\"");
				break;
			case '\\':
				sb.append("\\\\");
				break;
			case '/':
				sb.append("\\/");
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\r':
				sb.append("\\r");
				break;
			case '\t':
				sb.append("\\t");
				break;
			default:
				sb.append(c);
			}
		}
		sb.append('\"');
		return sb.toString();
	}

	/**
	 * Change a Number to JSON
	 * 
	 * @param number
	 *            Number
	 * @return a JSON String
	 */
	public static String number2Json(final Number number) {
		return number.toString();
	}

	/**
	 * Change Boolean to JSON
	 * 
	 * @param bool
	 *            Boolean
	 * @return a JSON String
	 */
	public static String boolean2Json(final Boolean bool) {
		return bool.toString();
	}

	/**
	 * Change Collection to JSON (List,Set)
	 * 
	 * @param c
	 *            a Collection Object
	 * @return a JSON String
	 */
	public static String collection2Json(final Collection<Object> c) {
		final Object[] arrObj = c.toArray();
		return toJson(arrObj);
	}

	/**
	 * 把list数据转换的json字符�?
	 * 
	 * @param labels
	 *            list数据
	 * @return 返回转换后的json字符�?
	 * @author xfzhou
	 */
	public static String collection2Json(final Object obj) {
		if (obj == null)
			return null;
		Gson gson = new Gson();

		return gson.toJson(obj);
	}

	/**
	 * 把json数据字符串，转换成list对象
	 * 
	 * @param str
	 *            json数据字符�?
	 * @return 返回list对象，元素是map对象
	 * @author xfzhou
	 */
	public static List<String> json2List(String str) {
		if (ValidateUtil.isEmpty(str))
			return null;

		Gson jsonObj = new Gson();
		Type listType = new TypeToken<List<String>>() {
		}.getType();

		return jsonObj.fromJson(str, listType);
	}

	/**
	 * Change Map<String, Object> to JSON
	 * 
	 * @param map
	 *            a Map
	 * @return a JSON String
	 */
	public static String map2Json(final Map<String, Object> map) {
		if (map.isEmpty()) {
			return "{}";
		}
		final StringBuilder sb = new StringBuilder(map.size() << 4);
		sb.append('{');
		final Set<String> keys = map.keySet();
		for (final String key : keys) {
			final Object value = map.get(key);
			sb.append('\"');
			sb.append(key); // Can not be special character
			sb.append('\"');
			sb.append(':');
			sb.append(toJson(value));
			sb.append(',');
		}
		// add last "}"
		sb.setCharAt(sb.length() - 1, '}');
		return sb.toString();
	}

	/**
	 * Change array to JSON
	 * 
	 * @param array
	 *            an Object array
	 * @return a JSON String
	 */
	public static String array2Json(final Object[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4); // the
		// power
		// of
		// four
		sb.append('[');
		for (final Object o : array) {
			sb.append(toJson(o));
			sb.append(',');
		}
		// change last "," to "]"
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change int array to JSON
	 * 
	 * @param array
	 *            a int array
	 * @return a JSON String
	 */
	public static String intArray2Json(final int[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final int o : array) {
			sb.append(Integer.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change long array to JSON
	 * 
	 * @param array
	 *            a long array
	 * @return a JSON String
	 */
	public static String longArray2Json(final long[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final long o : array) {
			sb.append(Long.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change boolean array to JSON
	 * 
	 * @param array
	 *            an boolean array
	 * @return a JSON String
	 */
	public static String booleanArray2Json(final boolean[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final boolean o : array) {
			sb.append(Boolean.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change float array to JSON
	 * 
	 * @param array
	 *            a float array
	 * @return a JSON String
	 */
	public static String floatArray2Json(final float[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final float o : array) {
			sb.append(Float.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change double array to JSON
	 * 
	 * @param array
	 *            an double array
	 * @return a JSON String
	 */
	public static String doubleArray2Json(final double[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final double o : array) {
			sb.append(Double.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	public static String shortArray2Json(final short[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final short o : array) {
			sb.append(Short.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change byte array to JSON
	 * 
	 * @param array
	 *            an byte array
	 * @return a JSON String
	 */
	public static String byteArray2Json(final byte[] array) {
		if (array.length == 0) {
			return "[]";
		}
		final StringBuilder sb = new StringBuilder(array.length << 4);
		sb.append('[');
		for (final byte o : array) {
			sb.append(Byte.toString(o));
			sb.append(',');
		}
		// set last ',' to ']':
		sb.setCharAt(sb.length() - 1, ']');
		return sb.toString();
	}

	/**
	 * Change an Object to JSON
	 * 
	 * @param bean
	 *            Object to json
	 * @return a JSON String
	 */
	public static String object2Json(final Object bean) {
		// check null
		if (bean == null) {
			return "{}";
		}
		final Method[] methods = bean.getClass().getMethods();
		final StringBuilder sb = new StringBuilder(methods.length << 4);
		// the power of four
		sb.append('{');

		for (final Method method : methods) {
			try {
				final String name = method.getName();
				String key = "";
				if (name.startsWith("get")) {
					key = name.substring(3);

					final String[] arrs = { "Class" };// prevention of endless
					// loop
					boolean bl = false;
					for (final String s : arrs) {
						if (s.equals(key)) {
							bl = true;
							continue;
						}
					}
					if (bl) {
						continue; // prevention of endless loop
					}
				} else if (name.startsWith("is")) {
					key = name.substring(2);
				}
				if (key.length() > 0 && Character.isUpperCase(key.charAt(0))
						&& method.getParameterTypes().length == 0) {
					if (key.length() == 1) {
						key = key.toLowerCase();
					} else if (!Character.isUpperCase(key.charAt(1))) {
						key = key.substring(0, 1).toLowerCase()
								+ key.substring(1);
					}
					final Object elementObj = method.invoke(bean);

					// System.out.println("###" + key + ":" +
					// elementObj.toString());

					sb.append('\"');
					sb.append(key); // can't content special character
					sb.append('\"');
					sb.append(':');
					sb.append(toJson(elementObj));
					sb.append(',');
				}
			} catch (final Exception e) {
				// e.getMessage();
				throw new RuntimeException("Packing Object Exception��"
						+ e.getMessage(), e);
			}
		}
		if (sb.length() == 1) {
			return bean.toString();
		} else {
			sb.setCharAt(sb.length() - 1, '}');
			return sb.toString();
		}
	}

	/**
	 * Change an Object to JSON,the jsonString has object name.
	 * 
	 * @param array
	 *            an int array
	 * @return a JSON String
	 */
	public static String object2JsonWithName(final Object bean) {
		StringBuffer objectContent = new StringBuffer(object2Json(bean));
		return objectContent.append(bean.getClass().getSimpleName()).toString();
	}

	/**
	 * 把json数据字符串，转换成map对象
	 * 
	 * @param jsonData
	 *            son数据字符�?
	 * @return 返回map对象
	 * @author xfzhou
	 */
	public static Map<String, String> json2Map(String jsonData) {
		if (ValidateUtil.isEmpty(jsonData))
			return null;

		Gson jsonObj = new Gson();
		Type mapType = new TypeToken<Map<String, String>>() {
		}.getType();

		return jsonObj.fromJson(jsonData, mapType);
	}

	/**
	 * 把json数据字符串，转换成list对象
	 * 
	 * @param fileInfoList
	 *            json数据字符�?
	 * @return 返回list对象，元素是map对象
	 * @author xfzhou
	 */
	public static List<Map<String, String>> json2MapList(String fileInfoList) {
		if (ValidateUtil.isEmpty(fileInfoList))
			return null;

		Gson jsonObj = new Gson();
		Type listType = new TypeToken<List<Map<String, String>>>() {
		}.getType();

		return jsonObj.fromJson(fileInfoList, listType);
	}
}
